SelectDataGridEditorController = Class.create(DataGridEditorController, {
  buildEditor: function ($super, name, columnDefinition) {
    var cellEditor = this._createEditorElement("select", name, "dataGridCellEditorSelect", {name: name}, columnDefinition);
    
    if (columnDefinition.required)
      cellEditor.addClassName("required");
    
    this._editorValueChangeListener = this._onEditorValueChange.bindAsEventListener(this);
    
    if (columnDefinition.options) {
      this._addOptionsFromArray(cellEditor, columnDefinition.options);
    }
    
    return cellEditor;
  },
  removeAllOptions: function (handlerInstance) {
    if (handlerInstance._editable) {
      for (var i = handlerInstance.options.length - 1; i >= 0; i--) {
        $(handlerInstance.options[i]).remove();
      }  
    }
  },
  addOption: function (handlerInstance, value, text) {
    return this.addOption(handlerInstance, value, text, false);
  },
  addOption: function (handlerInstance, value, text, selected) {
    if (handlerInstance._editable) {
      var optionNode = this._createOption(value, text, selected);
      handlerInstance.appendChild(optionNode);
      return optionNode;
    } else {
      handlerInstance._options.push({
        text: text,
        value: value
      });
      
      if (this.getEditorValue(handlerInstance) == value) {
        this._setViewerValue(handlerInstance, value, text);
      }
    }
  },
  _createOptionGroup: function (text) {
    return new Element("optgroup", {label:text});
  },
  _createOption: function (value, text, selected) {
    var optionNode;
    
    if (!selected)
      optionNode = new Element("option", {value: value === undefined ? '' : value});
    else
      optionNode = new Element("option", {value: value === undefined ? '' : value, selected: "selected"});
    
    if (text)
      optionNode.update(text);
    
    return optionNode;
  },
  attachContentHandler: function ($super, dataGrid, cell, handlerInstance) {
    var result = $super(dataGrid, cell, handlerInstance);
    if (this.getEditable(handlerInstance))
      Event.observe(result, "change", this._editorValueChangeListener);
    return result;
  },
  detachContentHandler: function ($super, handlerInstance) {
    if (this.getEditable(handlerInstance))
      Event.stopObserving(handlerInstance, "change", this._editorValueChangeListener);
    $super(handlerInstance);
  },
  buildViewer: function ($super, name, columnDefinition) {
    var cellViewer = this._createViewerElement("div", name, "dataGridCellViewerSelect", {}, columnDefinition);
    if (this.isDynamicOptions(cellViewer))
      cellViewer._options = new Array();
    
    return cellViewer;
  },
  disableEditor: function ($super, handlerInstance) {
    if (handlerInstance._editable != true)
      handlerInstance.addClassName("dataGridCellViewerDisabled");
    else {
      this._addDisabledHiddenElement(handlerInstance);
      handlerInstance.disabled = true;
    }
  },
  enableEditor: function ($super, handlerInstance) {
    if (handlerInstance._editable != true)
      handlerInstance.removeClassName("dataGridCellViewerDisabled");
    else {
      handlerInstance.disabled = false;
      this._removeDisabledHiddenElement(handlerInstance);
    }
  },
  getEditorValue: function ($super, handlerInstance) {
    if (handlerInstance._editable != true) 
      return this._getViewerValue(handlerInstance);
    else
      return handlerInstance.value;
  },
  getDisplayValue: function ($super, handlerInstance) {
    if (handlerInstance._editable != true) 
      return $super(handlerInstance);
    else {
      var index = handlerInstance.selectedIndex;
      var option = handlerInstance.options[index];
      if (option)
        return option.innerHTML;
      else
        return $super(handlerInstance);
    }
  },
  setEditorValue: function ($super, handlerInstance, value) {
    if (handlerInstance._editable != true) {
      var displayValue = value;
      var options = this.isDynamicOptions(handlerInstance) ? handlerInstance._options : handlerInstance._columnDefinition.options;
      
      if (options) {
        for (var i = 0; i < options.length; i++) {
          if (options[i].optionGroup == true) {
            for (var j = 0; j < options[i].options.length;j++) {
              if (options[i].options[j].value == value) {
                displayValue = options[i].options[j].text;
                break;
              }
            }
          } else {
            if (options[i].value == value) {
              displayValue = options[i].text;
              break;
            }
          }
        }
      }
      this._setViewerValue(handlerInstance, value, displayValue);
    } else {
      if (this.isDisabled(handlerInstance))
        this._updateDisabledHiddenElement(handlerInstance, value);
      
      handlerInstance.value = value;
    }
  },
  destroyEditor: function ($super, handlerInstance) {
    handlerInstance.remove();
  },
  isDisabled: function ($super, handlerInstance) {
    return handlerInstance.disabled == true;
  },
  isDynamicOptions: function (handlerInstance) {
    return handlerInstance._columnDefinition.dynamicOptions || false;
  },
  getDataType: function ($super) {
    return "select";  
  },
  getMode: function ($super) { 
    return DataGridControllers.EDITMODE_EDITABLE;
  },
  getOptions: function (handlerInstance) {
    if (this.getEditable(handlerInstance)) {
      return this._readOptionsToArray(handlerInstance);
    } else {
      return handlerInstance._options;
    }
  },
  setOptions: function (handlerInstance, options) {
    if (this.getEditable(handlerInstance)) {
      this.removeAllOptions(handlerInstance);
      this._addOptionsFromArray(handlerInstance, options);
    } else {
      handlerInstance._options = options;
    }
  },
  _onEditorValueChange: function (event) {
    var handlerInstance = Event.element(event);
    this._fireValueChange(handlerInstance, handlerInstance.value);
  },
  setEditable: function ($super, handlerInstance, editable) {
    if (this.getEditable(handlerInstance) == editable)
      return handlerInstance;
    
    if (!this.isDynamicOptions(handlerInstance))
      return $super(handlerInstance, editable);
    
    var value = this.getEditorValue(handlerInstance);
    var options;
    
    if (this.getEditable(handlerInstance)) {
      options = this._readOptionsToArray(handlerInstance);
    } else {
      options = handlerInstance._options;
    }

    var newInstance = $super(handlerInstance, editable);
      
    if (editable) {
      this._addOptionsFromArray(newInstance, options);
    } else {
      newInstance._options = options;
    }
    
    this.setEditorValue(newInstance, value);
    
    return newInstance;
  },
  copyCellValue: function($super, target, source) {
    if (!this.isDynamicOptions(source)) {
      $super(target, source);
    } else {
      var value = this.getEditorValue(source);
      var options;
      
      if (this.getEditable(source)) {
        options = this._readOptionsToArray(source);
      } else {
        options = source._options;
      }
  
      if (this.getEditable(target)) {
        this.removeAllOptions(target);
        this._addOptionsFromArray(target, options);
      } else {
        target._options = options;
      }
      
      this.setEditorValue(target, value);
    }
  },
  _addOptionsFromArray: function (cellEditor, options) {
    var elements = new Array();

    for (var j = 0, l = options.length; j < l; j++) {
      var option = options[j];
      if (option.optionGroup == true) {
        
        var optionGroup = this._createOptionGroup(option.text);

        var groupOptions = option.options;
        for (var groupIndex = 0; groupIndex < groupOptions.length; groupIndex++) {
          var optionElement = this._createOption(groupOptions[groupIndex].value, groupOptions[groupIndex].text, false);
          optionGroup.appendChild(optionElement);
        }
        
        elements.push(optionGroup);
      } else {
        elements.push(this._createOption(option.value, option.text, false));
      }
    }

    for (var i = 0, l = elements.length; i < l;i++) {
      cellEditor.appendChild(elements[i]);
    }
  },
  _readOptionsToArray: function (cellEditor) {
    var options = new Array();
    
    for (var i = 0, sourceChildNodeLen = cellEditor.childNodes.length; i < sourceChildNodeLen; i++) {
      var editorChildNode = cellEditor.childNodes[i];
      if (editorChildNode.tagName == 'OPTGROUP') {
        var groupOptions = new Array();
        
        for (var j = 0, groupChildNodeLen = editorChildNode.childNodes.length; j < groupChildNodeLen; j++) {
          var groupOption = editorChildNode.childNodes[k];
          groupOptions.push({
            text: groupOptionNode.text,
            value: groupOptionNode.value
          });
        }
        
        options.push({
          text: editorChildNode.text,
          optionGroup: true,
          options: groupOptions
        });
        
      } else if (editorChildNode.tagName == 'OPTION') {
        options.push({
          text: editorChildNode.text,
          value: editorChildNode.value
        });
      }
    }
    
    return options;
  } 
});

DataGridControllers.registerController(new SelectDataGridEditorController());